﻿using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows;

namespace WpfApp2
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        // 是否通过usb连接进行socket通信：true:是，false:通过局域网通信
        public bool isUseUsb = false;
        SocketClient client = null;
        // 通信端口
        string ipPort = "8800";
        // 使用USB通信时，手机端口
        string phoneIPPort = "36103";
        // 修改按钮状态
        public bool isSocketConn = false;
        // 用于在子线程中刷新UI线程
        public SynchronizationContext m_SyncContext = null;
        // 使用局域网通信时，对应安卓设备IP
        public string localNetIp = "192.168.31.129";

        public MainWindow()
        {
            InitializeComponent();
            m_SyncContext = SynchronizationContext.Current;
            ChangeBtnEnabled(null);
        }

        // 按钮点击事件
        private void BtnSend_Click(object sender, RoutedEventArgs e)
        {
            Console.WriteLine("BtnSend_Click：" + sender);
            if (client != null)
                client.SendMsg(Encoding.UTF8.GetBytes("PC发送的数据"));
        }

        private void BtnSocketDisConnect_Click(object sender, RoutedEventArgs e)
        {
            Console.WriteLine("BtnSocketDisConnect_Click：" + sender);

            if (client != null)
                client.SendMsg(SocketDataConst.MSG_SOCKET_CONNECT
                    + SocketDataConst.MSG_KEY_VALUE_SPLIT_STRING + SocketDataConst.MSG_FAILED,
                    SocketDataConst.MSG_TYPE_LAST_BYTE);
        }

        private void BtnSocketConnect_Click(object sender, RoutedEventArgs e)
        {
            // usb通信需要
            if (isUseUsb)
            {
                Console.WriteLine("BtnSocketConnect_Click：" + sender + ", client=" + client);
                string result = CmdExcute(@"adb forward tcp:" + ipPort + " tcp:" + phoneIPPort);
                Console.WriteLine("result：" + result);
            }

            client = new SocketClient(ipPort, this);
            client.Connect();
            if (client != null)
                client.Listen();
        }

        // 执行cmd命令,使用usb连接时需要执行
        private string CmdExcute(string strInput)
        {
            strInput = strInput.Trim() + "&exit";
            Process p = new Process();  //设置要启动的应用程序
            p.StartInfo.FileName = "cmd.exe";//是否使用操作系统shell启动
            p.StartInfo.UseShellExecute = false; // 接受来自调用程序的输入信息
            p.StartInfo.RedirectStandardInput = true;  //输出信息
            p.StartInfo.RedirectStandardOutput = true; // 输出错误
            p.StartInfo.RedirectStandardError = false; //显示程序窗口，必须为false，否则某些命令无法正常执行
            p.StartInfo.CreateNoWindow = true;//启动程序
            p.Start();
            p.StandardInput.WriteLine(strInput);
            p.StandardInput.AutoFlush = true;
            //获取输出信息
            StreamReader reader = p.StandardOutput;//截取输出流
            string strOuput = reader.ReadToEnd();
            //等待程序执行完退出进程
            p.WaitForExit();
            p.Close();
            reader.Close();
            //error.Close();
            return strOuput.Trim();
        }

        // 根据状态决定按钮的可用性
        public void ChangeBtnEnabled(object text)
        {
            Console.WriteLine("ChangeBtnEnabled：isSocketConn=" + isSocketConn);

            BtnConn.IsEnabled = !isSocketConn;
            BtnDisConn.IsEnabled = isSocketConn;
            BtnSendData.IsEnabled = isSocketConn;
        }
    }

    class SocketClient
    {
        Socket client = null;
        private static Encoding encode = Encoding.UTF8;
        private readonly string ipPort = "";
        MainWindow main;

        public SocketClient(string ipPort, MainWindow main)
        {
            this.main = main;
            this.ipPort = ipPort;
            if (client == null)
                client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        }

        public void Connect()
        {
            if (client != null)
            {
                try
                {
                    // 通过usb通信
                    IPAddress myIP = IPAddress.Parse("127.0.0.1");
                    // 通过局域网通信，请配置正确ip，并使设备和PC处于同一局域网
                    if (!main.isUseUsb)
                        myIP = IPAddress.Parse(main.localNetIp);

                    IPEndPoint EPhost = new IPEndPoint(myIP, int.Parse(ipPort));
                    client.Connect(EPhost);
                    // 默认是65536
                    Console.WriteLine("Connect：receive buffer size=" + client.ReceiveBufferSize + ", send buffer size =" + client.SendBufferSize);
                    client.ReceiveBufferSize = 1048576;
                    Console.WriteLine("Connect：after set, receive buffer size=" + client.ReceiveBufferSize + ", send buffer size =" + client.SendBufferSize);
                }
                catch (Exception e)
                {
                    MessageBox.Show("连接失败:" + e.Message);
                }
            }
        }

        public void DisConnect()
        {
            if (client != null)
            {
                client.Disconnect(true);
                client.Close();
                client = null;
            }
        }

        // 一次获取数据最大长度，soket一次最长能传输的是65536字节
        int oneTimeDataMaxLen = 1048576;//65536;

        private void ProcessSocketData(byte[] tmpdata, int oneTimeDataLen)
        {
            // 有用数据: 当传过来的数据没有完全填满t_data数组时，有用数据比t_data更少。
            byte[] usefulData = new byte[oneTimeDataLen];
            Array.Copy(tmpdata, usefulData, oneTimeDataLen);

            string data = Encoding.UTF8.GetString(usefulData, 0, usefulData.Length);
            Console.WriteLine("ProcessSocketData received data=" + data);

            // 只有不到300字节的数据，则认为是消息数据，否则是预览数据，消息长度不超过300字节
            if (oneTimeDataLen < 300 && usefulData[usefulData.Length - 1] == SocketDataConst.MSG_TYPE_LAST_BYTE)
            {
                ProcessMsg(usefulData);
            }
            else
            {
                MessageBox.Show("收到设备数据:" + data);
            }
        }

        public void Listen()
        {
            Thread listenThread = new Thread(delegate ()
            {
                Console.WriteLine("listenThread start");
                // 缓存获取一次的数据
                byte[] tmpdata = new byte[oneTimeDataMaxLen];
                int oneTimeDataLen = 0;

                try
                {
                    // 接收数据
                    while (client != null && (oneTimeDataLen = client.Receive(tmpdata)) != 0)
                    {
                        ProcessSocketData(tmpdata, oneTimeDataLen);
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine("listen error：" + e.Message + e);
                }
                Console.WriteLine("listenThread end");
                // 设备主动断开连接了
                if (main.isSocketConn)
                {
                    DisConnect();
                    main.isSocketConn = false;
                    main.m_SyncContext.Post(main.ChangeBtnEnabled, null);
                    MessageBox.Show("设备主动断开连接");
                }
            });
            listenThread.Start();
        }

        public void SendMsg(string data, byte lastByte)
        {
            try
            {
                byte[] rawData = encode.GetBytes(data);
                byte[] sendData = new byte[rawData.Length + 1];
                sendData[sendData.Length - 1] = lastByte;
                Array.Copy(rawData, sendData, rawData.Length);
                client.Send(sendData);
                Console.WriteLine("sendMsg：" + data);
            }
            catch (Exception e)
            {
                Console.WriteLine("sendMsg error：" + e);
            }
        }

        public void SendMsg(byte[] data)
        {
            try
            {
                client.Send(data);
                Console.WriteLine("sendMsg：" + data);
            }
            catch (Exception e)
            {
                Console.WriteLine("sendMsg error：" + e);
            }
        }

        private void ProcessMsg(byte[] msg)
        {
            if (msg == null || msg.Length < 2)
                return;
            // 去除最后一个无用字节，获取消息内容
            string result = Encoding.UTF8.GetString(msg, 0, msg.Length - 1);
            string[] splits = result.Split(SocketDataConst.MSG_KEY_VALUE_SPLIT_STRING.ToCharArray());
            if (splits != null && splits.Length > 1)
            {
                string key = splits[0];
                string value = splits[1];
                switch (key)
                {
                    case SocketDataConst.MSG_SOCKET_CONNECT_STATE:
                        if (value.Equals(SocketDataConst.MSG_SUCCESS))
                        {
                            main.isSocketConn = true;
                        }
                        else if (value.Equals(SocketDataConst.MSG_SUCCESS))
                        {
                            main.isSocketConn = false;
                        }
                        main.m_SyncContext.Post(main.ChangeBtnEnabled, null);
                        if (main.isSocketConn)
                            MessageBox.Show("连接成功");
                        else
                            MessageBox.Show("连接失败");
                        break;
                    case SocketDataConst.MSG_SOCKET_DISCONNECT_STATE:
                        if (value.Equals(SocketDataConst.MSG_SUCCESS))
                        {
                            // PC端断开
                            DisConnect();
                            main.isSocketConn = false;
                        }
                        else
                        {
                            //main.isSocketConn = true; 
                        }
                        main.m_SyncContext.Post(main.ChangeBtnEnabled, null);
                        if (!main.isSocketConn)
                            MessageBox.Show("断开连接成功");
                        else
                            MessageBox.Show("断开连接失败");
                        break;

                }
            }
        }
    }

    /**
     * @author ：zuhui.zhang
     * time ： 2021/5/24 15:51
     * 定义soket通信过程中，数据规则
     */
    class SocketDataConst
    {
        // 字节数据最后一个字节的值为4时，认为是消息数据。因为消息数据比较少，所以用最后一个字节区分
        public const byte MSG_TYPE_LAST_BYTE = 4;
        //消息状态值
        public const string MSG_SUCCESS = "true";
        public const string MSG_FAILED = "false";
        // 消息key和value连接符，消息字符串类似：msg_connect_state:true，表示连接成功
        public const string MSG_KEY_VALUE_SPLIT_STRING = ":";
        // socket连接时的状态，true连接成功，false连接失败
        public const string MSG_SOCKET_CONNECT_STATE = "msg_socket_connect_state";
        // socket断开连接时的状态，true 断开成功
        public const string MSG_SOCKET_DISCONNECT_STATE = "msg_socket_disconnect_state";
        
        // pc发送断开连接消息给设备，true：去连接，false，断开连接
        public const string MSG_SOCKET_CONNECT = "msg_socket_connect";
    }
}
